package example.rmi;

import java.rmi.RemoteException;
import java.util.HashMap;

import util.AgregadorRMI;
import controlador.buzones.Buzon;
import controlador.buzones.BuzonIface;
import controlador.buzones.Mensaje;

/**
 * 
 * @author Globex Inc.
 *
 */
public class Broker {
	
	private BuzonIface _buzon;
	private HashMap<String, BuzonIface> _slaves;
	
	public Broker(int port, String id) throws Exception {
		_buzon = new Buzon();
		if(!_buzon.registrar(port, id)) {
			System.err.println("Cannot register this shit");
			System.exit(-1);
		}
		
		_slaves = new HashMap<String, BuzonIface>();
	}
	
	public BuzonIface getBuzon() {
		return _buzon;
	}
	
	/**
	 * 
	 * @return true si hay mensajes y false si no han habido mensajes
	 * @throws Exception
	 */
	public boolean procesarMensajes() throws Exception {
		Mensaje msj = _buzon.desencolar();
		boolean ans = false;
		
		if(msj != null) {
			System.out.println("Message received from "+msj.get_source());
			
			switch(msj.get_type()) {
				case BEFRIEND:
					befriend(msj.get_message());
					break;
				case UNFRIEND:
					unfriend(msj.get_source());
			}
			
			/*if(msj.get_type() == MessageTypes.BEFRIEND) {
				befriend(msj.get_message());
			}*/
		}
		
		return ans;
	}
	
	
	//public void befriend(String host, int port, String id) throws InterruptedException {
	public void befriend(HashMap<String, String> pairs) throws InterruptedException {	
		String host = pairs.get("registry:host");
		int port = Integer.parseInt(pairs.get("registry:port"));
		String id = pairs.get("registry:path");
		
		System.out.println("Getting mailbox at "+host+":"+port+"/"+id);
		
		BuzonIface otro = null;
		int tries = 1;
		while(otro == null) {
			System.out.println("Retrieval attemp "+(tries++));
			try {
				otro = (BuzonIface) AgregadorRMI.obtenerRemoto(host, port, id);
				_slaves.put(id, otro);
				System.out.println("Mailbox retrieved from "+host+":"+port+"/"+id);
			} catch(Exception e){
				e.printStackTrace();
			}
			
			Thread.sleep(1000);
		}
		
		System.out.println("Got mailbox from "+host+":"+port+"/"+id);
	}
	
	public void unfriend(String id){
		_slaves.remove(id);
	}
	
	public boolean bcast(Mensaje msj) {
		boolean ans = false;

		try {
			if(!_slaves.isEmpty()) {
				for(BuzonIface b : _slaves.values()) {
					b.encolar(msj);
				}
				ans = true;
			}
		} catch (RemoteException e) {
			ans = false;
		}

		return ans;
	}
	
	public boolean sendMessage(Mensaje msj) {
		boolean ans = false;
		String receptor = msj.get_target();
		try {
			_slaves.get(receptor).encolar(msj);
			ans = true;
		} catch (RemoteException e) {
			e.printStackTrace();
		}
		
		return ans;
	}
	
	/**
	 * @param
	 * 0 puerto
	 * 1 id para rmi  
	 */
	public static void main(String[] args) {
		
		int localPort = Integer.parseInt(args[0]);
		String localID = args[1];
		
		try {
			Broker master = new Broker(localPort, localID);
			HashMap<String, String> content = new HashMap<String, String>();
			int count = 1;
			content.put("Test message number ", ""+count);
			Mensaje msj = new Mensaje();
			msj.set_source(localID);
			msj.set_target("bcast");
			msj.set_message(content);
			while(true) {
				master.procesarMensajes();
				if(master.bcast(msj)) {
					System.out.println(count+ " messages sent since boot");
					count++;
					content.put("Test message number ", ""+count);
					msj = new Mensaje();
					msj.set_source(localID);
					msj.set_target("bcast");
					msj.set_message(content);
				}
				
				Thread.sleep(1000);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
